package edu.asu.sapa.ground.update;

import edu.asu.sapa.Planner;
import edu.asu.sapa.ground.MathForm;
import edu.asu.sapa.ground.Operator;
import edu.asu.sapa.ground.Proposition;
import edu.asu.sapa.ground.State;
import edu.asu.sapa.heuristic.PG;


public class Test extends Constraint {
	public int op;
	public MathForm leftSide; // Ground Function ID of the left side
	public MathForm rightSide;
	public boolean isConstant;
	public boolean value;

	// public Test() {
	// op = 0;
	// leftSide = null;
	// rightSide = null;
	// }

	public Test(int c, MathForm left, MathForm right) {
		op = c;
		leftSide = left;
		rightSide = right;
	}

	public boolean analyzeStatic(float dur) {
		isConstant = false;
		boolean isConstant = true;
		isConstant &= leftSide.analyzeStatic(dur);
		isConstant &= rightSide.analyzeStatic(dur);
		if (isConstant) {
			this.isConstant = isConstant;
			value = holdsBefore(null,null);
			return value;
		}
		return true;
	}

	final private void makeTop() {
		op = 0;
		leftSide = new MathForm(0f);
		rightSide = new MathForm(0f);
	}
	final private void makeBot() {
		op = 0;
		leftSide = new MathForm(0f);
		rightSide = new MathForm(1f);
	}

	/** Set the Comparator: "==" : 0; "<" : 1; "<=" : 2; ">" : 3; ">=" : 4; */
	public void setComparator(int i) {
		op = i;
	}

	public int getComparator() {
		return op;
	}

	// obsolete?
	public Test bind(float start, float duration, float end) {
		MathForm l = leftSide.bind(start, duration, end);
		MathForm r = rightSide.bind(start, duration, end);
		if (l != leftSide || r != rightSide)
			return new Test(op, l, r);
		return this;
	}

	public void relaxedUpdate(PG pg, State s, Context c, float time) {
	}
	public void relaxedStart(PG pg, State s, Context c, float time) {
	}
	public void relaxedFinish(PG pg, State s, Context c, float time) {
	}
	
	public boolean updateBefore(State s, Context c, float time) {
		switch (op) {
		case 0:
			return leftSide.value(s,c) == rightSide.value(s,c);
		case 1:
			return leftSide.value(s,c) < rightSide.value(s,c);
		case 2:
			return leftSide.value(s,c) <= rightSide.value(s,c);
		case 3:
			return leftSide.value(s,c) > rightSide.value(s,c);
		case 4:
			return leftSide.value(s,c) >= rightSide.value(s,c);
		default:
			return false;
		}
	}
	public boolean updateAfter(State s, Context c, float time) {
		switch (op) {
		case 0:
			return leftSide.value(s,c) == rightSide.value(s,c);
		case 1:
			return leftSide.value(s,c) < rightSide.value(s,c);
		case 2:
			return leftSide.value(s,c) <= rightSide.value(s,c);
		case 3:
			return leftSide.value(s,c) > rightSide.value(s,c);
		case 4:
			return leftSide.value(s,c) >= rightSide.value(s,c);
		default:
			return false;
		}
	}
	
	public boolean startBefore(State s, Context c, float time) {
		s.addConstraint(this,c);
		return true;
	}
	public boolean startAfter(State s, Context c, float time) {
		s.addConstraint(this,c);
		return true;
	}
	public boolean finishBefore(State s, Context c, float time) {
		return s.removeConstraint(this,c);
	}
	public boolean finishAfter(State s, Context c, float time) {
		return s.removeConstraint(this,c);
	}
	
	public final boolean applicableBefore(State s, Context c) {
		return holdsBefore(s,c);
	}
	public final boolean applicableAfter(State s, Context c) {
		return holdsAt(s,c);
	}

	public boolean holdsAt(State s, Context c) {
		switch (op) {
		case 0:
			return leftSide.value(s,c) == rightSide.value(s,c);
		case 1:
			return leftSide.value(s,c) < rightSide.value(s,c);
		case 2:
			return leftSide.value(s,c) <= rightSide.value(s,c);
		case 3:
			return leftSide.value(s,c) > rightSide.value(s,c);
		case 4:
			return leftSide.value(s,c) >= rightSide.value(s,c);
		default:
			return false;
		}
	}
	public boolean holdsBefore(State s, Context c) {
		switch (op) {
		case 0:
			return leftSide.value(s,c) == rightSide.value(s,c);
		case 1:
			return leftSide.value(s,c) < rightSide.value(s,c);
		case 2:
			return leftSide.value(s,c) <= rightSide.value(s,c);
		case 3:
			return leftSide.value(s,c) > rightSide.value(s,c);
		case 4:
			return leftSide.value(s,c) >= rightSide.value(s,c);
		default:
			return false;
		}
	}
	
	/** Function to do short printing */
	public String toString() {
		String s = "(";

		s += op + " " + leftSide + " " + rightSide + ")";

		return s;
	}

	public int compareTo(Test o) {
		// assert this != null && o != null;
		// constants should go first if they can be false;
		// otherwise they should go last.
//		if (isConstant) {
//			if (o.isConstant) {
//				if (value) {
//					if (o.value)
//						return 0;
//					return 1;
//				}
//				if (o.value)
//					return -1;
//				return 0;
//			}
//			if (value)
//				return 1;
//			return -1;
//		}
//		if (o.isConstant) {
//			if (o.value)
//				return -1;
//			return 1;
//		}
		return 0;
	}
	public int compareTo(Update u) {
		return compareTo((Test)u);
	}
	
	public void removeDependencies(Operator o) {
	}
	public void setDependencies(Operator o) {
	}

	@Override
	public boolean isFail() {
		return isConstant && !value;
	}

	@Override
	public boolean isNoOp() {
		return isConstant && value;
	}

	
}
